package com.allwees.bs.module.pms.service.impl;

import com.allwees.bs.core.model.constant.CacheName;
import com.allwees.bs.core.modelbase.branch.EBranchType;
import com.allwees.bs.module.core.req.BaseAuditReq;
import com.allwees.bs.module.pms.dao.SkuDao;
import com.allwees.bs.module.pms.dto.ProductDto;
import com.allwees.bs.module.pms.entity.Product;
import com.allwees.bs.module.pms.req.AuditProductReq;
import com.allwees.bs.module.pms.req.ProductForbidTheSaleReq;
import com.allwees.bs.module.pms.req.ProductLiftBanSaleReq;
import com.allwees.bs.module.pms.req.query.ExportGaSkuQueryReq;
import com.allwees.bs.module.pms.service.PlatformProductService;
import com.allwees.bs.module.pms.vo.ExportGaSkuVo;
import com.allwees.bs.module.pms.wf.ERetailerProductAction;
import com.allwees.bs.module.pms.wf.ERetailerProductState;
import com.allwees.bs.module.pms.wf.ESupplierProductAction;
import com.allwees.bs.module.pms.wf.ESupplierProductState;
import com.allwees.core.cache.RedisUtil;
import com.allwees.core.common.constant.EAuditResult;
import com.allwees.core.common.constant.EStatus;
import com.allwees.core.wf.Action;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.util.List;
import java.util.Set;

/**
 * @author yangylsky
 * @since 2019-08-21
 */
@Slf4j
@Service
public class PlatformProductServiceImpl extends BaseProductServiceImpl implements PlatformProductService {

    @Resource
    private SkuDao skuDao;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int audit(AuditProductReq req) {
        List<Product> products = findByUuids(req.getProductUuids());
        int succcessNum = 0;
        for (Product product : products) {
            if (audit(product, req)) {
                succcessNum++;
            }
        }
        return succcessNum;
    }

    protected boolean audit(Product product, BaseAuditReq req) {
        Assert.notNull(product, "product must not be a null");
        Assert.isTrue(EStatus.WAIT_AUDIT.equals(product.getEStatus()), "当前product状态[" + product.getEStatus() + "]不能执行审核");
        product.signal(_getAuditAction(product, req.getResult()), req.getBranchUserUuid(), req.getReason(), req.getRemark(), req.getPhotos());
        if (product.isNormal()) {
            setPublishInfo(product);//Dead code
        }
        return updateByUuid(product);
    }

    private Action _getAuditAction(Product product, EAuditResult result) {
        EBranchType wfType = product.getMerchantWfType();
        if (wfType == null) {
            throw new IllegalArgumentException("null wfType of Product:" + product.getNo());
        }
        switch (wfType) {
            case SUPPLIER:
                product.assertState(ESupplierProductState.WAIT_AUDIT);
                switch (result) {
                    case APPROVED:
                        return ESupplierProductAction.PLATFORM_AUDIT_APPROVED;
                    case REJECTED:
                        return ESupplierProductAction.PLATFORM_AUDIT_REJECTED;
                    default:
                        throw new IllegalArgumentException("invalid AuditResult:" + result);
                }
            case RETAILER:
                product.assertState(ERetailerProductState.WAIT_AUDIT);
                switch (result) {
                    case APPROVED:
                        return ERetailerProductAction.PLATFORM_AUDIT_APPROVED;
                    case REJECTED:
                        return ERetailerProductAction.PLATFORM_AUDIT_REJECTED;
                    default:
                        throw new IllegalArgumentException("invalid AuditResult:" + result);
                }
            default:
                throw new IllegalArgumentException("invalid wfType:" + wfType);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean puton(Product product, String operatorUuid) {
        product.assertStatus(EStatus.AUDIT_APPROVED);

        EBranchType wfType = product.getMerchantWfType();
        if (wfType == null) {
            throw new IllegalArgumentException("null wfType of Product:" + product.getNo());
        }
        switch (wfType) {
            case SUPPLIER:
                product.signal(ESupplierProductAction.PLATFORM_CONFIRM_PUTON, operatorUuid);
                break;
            case RETAILER:
                product.signal(ERetailerProductAction.PLATFORM_CONFIRM_PUTON, operatorUuid);
                break;
            default:
                throw new IllegalArgumentException("invalid wfType:" + wfType);
        }
        setPublishInfo(product);
        return updateByUuid(product);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean putoff(Product product) {
        product.assertStatus(EStatus.NORMAL);
        product.setEStatus(EStatus.PUTOFF_QA_FAILURE);
        return updateByUuid(product);
    }

    @Override
    public Set<String> allForbiddenUuids() {
        return baseMapper.allForbiddenUuids();
    }

    @Override
    public List<ExportGaSkuVo> exportGaSkus(ExportGaSkuQueryReq req) {
        return skuDao.queryGaSkus(req);
    }

    @Override
    public void forbidTheSale(ProductForbidTheSaleReq req) {
        List<Product> products = findByUuids(req.getProductUuids());
        for (Product product : products) {
            if (_forbidSale(product)) {
                ProductDto productDto = ProductDto.of(product);
                productDto.setOperatorUuid(req.getBranchUserUuid());
                productDto.setReason(req.getReason());
                productOnoffLogService.logForbidSale(productDto);
                RedisUtil.del(CacheName.PROD_PRODUCT_DETAILS + "::" + product.getUuid());
            }
        }
    }

    @Override
    public void liftBan(ProductLiftBanSaleReq req) {
        List<Product> products = findByUuids(req.getProductUuids());
        for (Product product : products) {
            if (_liftBan(product)) {
                ProductDto productDto = ProductDto.of(product);
                productDto.setOperatorUuid(req.getBranchUserUuid());
                productOnoffLogService.logLiftBan(productDto);
            }
        }
    }

    private boolean _liftBan(Product product) {
        product.setEStatus(EStatus.CREATED);
        Product update = new Product();
        update.setUuid(product.getUuid());
        update.setEStatus(EStatus.CREATED);
        return updateByUuid(update);
    }

    private boolean _forbidSale(Product product) {
        Product update = new Product();
        update.setUuid(product.getUuid());
        update.setEStatus(EStatus.DISABLED_FORBID_SALE);
        return updateByUuid(update);
    }
}
